Skip to content

Repair one room candidate with one provider call (#173 PR 1) - #288

Merged
memtomem merged 5 commits into
mainfrom
feat/room-repair-engine
Nov 10, 2026
Merged

memtomem merged 5 commits into
mainfrom
feat/room-repair-engine

Conversation

@memtomem

@memtomem memtomem commented Nov 9, 2026 •

Copy link
Copy Markdown
Owner

Summary

First delivery of #173: syncmill room repair runs only the member that produced a candidate, from that candidate. The result is a new candidate, verified again, that you compare and select yourself. Other members, their candidates and the source stay as they were.

syncmill room repair CAND --prompt "what to change" --preview
syncmill room repair CAND --prompt "what to change" --confirm TOKEN

Refs #173. This is PR 1 of the design in docs/room-targeted-repair-plan.md. Still to come: feedback requests (PR 2), room diff --against (PR 3), the TUI and --detach (PR 4).

How it holds together

  • The preview starts nothing. The token is the digest of a plan: room revision, candidate and digests, member, provider settings, session, --cold, task, lessons and gate. --confirm rebuilds the plan and runs only on an equal token.
  • Changes after confirmation refuse. start_round(repair_guard=) re-derives the revision, the parent rules and the stored session in the transaction that inserts the round, so nothing starts.
  • Anything that could only fail after the lease is refused at the preview. That includes a prompt that overflows only once rendered, and lessons that do not fit. A refusal cannot freeze the room.
  • Records. Repair rounds write provenance v3 and all-member rounds keep writing v2. round_expected_members narrows conversation records and _missing_members to the target of a believed repair, so a damaged record keeps today's warnings.
  • Sessions. --cold clears the target's session alone. A provider that cannot resume produces a failed candidate, and the parent stays repairable.

Departures from the approved design

The design was approved before #273 merged, and #273 moved its premise. All three are recorded in the design doc.

  1. The checkout is rebuilt only when it differs from the parent's patch, not always. Measured after fix(gates): keep what a gate writes out of the candidate (#268) #273: a gate writing only an ignored file leaves the tree equal to the candidate with ignored files kept, and a gate writing a visible file is already rebuilt at round end. An unconditional rebuild would only delete ignored files such as .venv. A failed attempt's leftovers still trigger a rebuild. The always-rebuild option is a one-line change if you prefer it.
  2. No core.hooksPath flags. fix(gates): keep what a gate writes out of the candidate (#268) #273 dropped them on purpose, and capture_changes runs repository-local hooks from the control repository #269 owns hooks.
  3. The shared helper already existed (rebuild_worktree).

Measured with real providers

Claude Code 2.1.319, Codex CLI 0.167.0 and Kimi Code 2.5.2, in one-member rooms with a gate, on macOS, 8 provider launches. Round 1's prompt holds a random codeword, and a file is left in the checkout to force a rebuild.

Provider Session workspace.rebuilt Left-behind file at launch / in patch Codeword Time
Claude resume 1 no / no returned 12.1 s
Codex resume 1 no / no returned 21.4 s
Kimi Code resume 1 no / no returned 24.4 s
  • Claude with a matching checkout: no rebuild, and an ignored file stayed.
  • Codex with an unknown session id: a failed candidate in 2.5 s with no fallback to a new conversation. The room stayed awaiting_decision, and --cold --preview worked.

These ran before the TUI commit, which does not touch the repair path, and before the merge with main. Linux was not run.

Test plan

  • Full suite with suite-run on the merge with main: CLEAN (exit 0)
  • 11 behaviours removed one at a time; each made tests/test_room_repair.py fail. The TUI fix was checked the same way against its own test
  • End-to-end through the real CLI with fake provider binaries: create, round, preview, confirm, compare, select, apply --verify, judge
  • Real-provider smoke, above

Review

Codex, with each finding checked against the source:

  • Plan, 2 rounds: 5 Major. Three changed the plan: the unguarded no-lessons size check, --cold missing from the token, and a smoke that would not have forced a rebuild. Two were already avoided by the code and are now pinned by tests.
  • Implementation, 3 rounds: SHIP with 0 findings on the diff; then 1 Major from a round aimed at the unchanged code; then SHIP on the fix. That finding was the TUI round dialog prefilling a repair's prompt as every member's default, fixed in the second commit.

All of these reviewed the branch before its merge with main. That merge brought tests and fixtures, and one conflict in docs/architecture/persisted-contracts.md.

🤖 Generated with Claude Code

memtomem and others added 5 commits November 9, 2026 19:53
`room repair CAND --prompt ... --preview` shows what would run and prints a
token; `--confirm TOKEN` runs it only if a plan rebuilt at that moment is
identical. Only the member that produced the candidate runs, from that
candidate, and the result is a new candidate, verified again, that the user
compares and selects. Peers, their candidates and the source stay as they were.

The claim's transaction re-derives the revision, the parent rules and the stored
session, so a change after confirmation refuses before a round exists. A task
that would only overflow once rendered is refused at the preview, where it
cannot freeze the room.

Repair rounds write provenance v3; all-member rounds keep writing v2.
`round_expected_members` narrows conversation records and `_missing_members` to
the target of a believed repair, so a damaged record keeps today's warnings.

This departs from the approved design in three places, because #273 merged after
it. A retained worktree now holds its candidate, so the checkout is rebuilt only
when it differs, which keeps ignored files in the common case. No hook flags
(#269 owns hooks). `rebuild_worktree` already existed.

Measured with real Claude, Codex and Kimi Code: resume survives a forced rebuild,
and an unknown session fails rather than starting a new conversation.

Refs #173

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The round dialog prefilled the latest round's prompt. After a repair that is an
instruction written for one member about its own candidate, and accepting the
default sent it to every member. Offer the last all-member round's prompt, and
say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	docs/architecture/persisted-contracts.md
# Conflicts:
#	docs/architecture/persisted-contracts.md
# Conflicts:
#	docs/architecture/persisted-contracts.md
@memtomem
memtomem merged commit 499be5d into main Nov 10, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant